package org.xx.armory.db.junit.impl;

import org.xx.armory.db.DbException;
import org.xx.armory.db.junit.DbUnitHelper;

import javax.sql.DataSource;
import java.math.BigInteger;

import static org.xx.armory.commons.Validators.notBlank;

/**
 * 用于Oracle数据库的单元测试工具类。
 *
 * @author Haart
 */
public class OracleDbUnitHelper
        extends AbstractDbUnitHelper
        implements DbUnitHelper {

    /**
     * 构造用于Oracle数据库的单元测试工具类。
     *
     * @param dataSource
     *         此工具类使用的数据源。
     * @throws NullPointerException
     *         如果参数{@code dataSource}是{@code null}。
     */
    public OracleDbUnitHelper(
            DataSource dataSource
    ) {
        super(dataSource);
    }

    /**
     * 构造{@code OracleDbUnitHelper}类型实例。
     *
     * @param url
     *         连接数据库的URL, 会被正规化。
     * @param user
     *         连接数据库的用户名, 会被正规化。
     * @param password
     *         连接数据库的口令, 会被正规化。
     * @throws NullPointerException
     *         如果参数{@code url}是{@code null}, 或者参数{@code user}是{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code url}只包含空白字符, 或者参数{@code user}只包含空白字符。
     */
    public OracleDbUnitHelper(
            String url,
            String user,
            String password
    ) {
        super(url, user, password);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected String wrap(
            String identity
    ) {
        return "\"" + identity + "\"";
    }

    /**
     * 重置序列
     *
     * @param name
     *         序列的名称
     * @throws DbException
     *         如果重置序列时出现SQL命令错误。
     * @see #resetSequence(String, Long, Long, Long)
     */
    public final void resetSequence(
            String name
    ) {
        this.resetSequence(name, null, null, null);
    }

    /**
     * 重置序列
     *
     * @param name
     *         序列的名称
     * @param value
     *         最小值。
     * @throws DbException
     *         如果重置序列时出现SQL命令错误。
     * @see #resetSequence(String, Long, Long, Long)
     */
    public final void resetSequence(
            String name,
            long value
    ) {
        this.resetSequence(name, value, value, null);
    }

    /**
     * 重置序列
     *
     * @param name
     *         序列的名称
     * @param minValue
     *         序列的最小值, 如果此参数的值是{@code null}则最小值为{@code 1}。
     * @param startValue
     *         序列的起始值, 如果此参数的值是{@code null}则起始值等于最小值{@code minValue}。
     * @param stepValue
     *         序列的每次增加值, 如果此参数的值是{@code null}则每次增加值为{@code 1}。
     * @throws IllegalArgumentException
     *         如果参数{@code name}是{@code null}或者只包含空白字符。
     * @throws DbException
     *         如果重置序列时出现SQL命令错误。
     * @see #resetSequence(String, Long, Long, Long, Long)
     */
    public final void resetSequence(
            String name,
            Long minValue,
            Long startValue,
            Long stepValue
    ) {
        name = notBlank(name, "name").trim();

        this.resetSequence(name, minValue, null, startValue, stepValue);
    }

    /**
     * 重置序列
     *
     * @param name
     *         序列的名称
     * @param minValue
     *         序列的最小值, 如果此参数的值是{@code null}则最小值为{@code 1}。
     * @param maxValue
     *         序列的最大值, 如果此参数的值是{@code null}则最大值是{@code 9999999999999999999999999999}。
     * @param startValue
     *         序列的起始值, 如果此参数的值是{@code null}则起始值等于最小值{@code minValue}。
     * @param stepValue
     *         序列的每次增加值, 如果此参数的值是{@code null}则每次增加值为{@code 1}。
     * @throws IllegalArgumentException
     *         如果参数{@code name}是{@code null}或者只包含空白字符。
     * @throws DbException
     *         如果重置序列时出现SQL命令错误。
     */
    public final void resetSequence(
            String name,
            Long minValue,
            Long maxValue,
            Long startValue,
            Long stepValue
    ) {
        name = notBlank(name, "name").trim().toUpperCase();

        final BigInteger bMinValue = checkBigInteger(minValue, 1);
        final BigInteger bMaxValue = checkBigInteger(maxValue, "9999999999999999999999999999");
        final BigInteger bStartValue = checkBigInteger(startValue, bMinValue.longValue());
        final BigInteger bStepValue = checkBigInteger(minValue, 1);

        ddl("DROP SEQUENCE " + wrap(name));

        ddl("CREATE SEQUENCE " + wrap(name)
                    + " MINVALUE " + bMinValue + " MAXVALUE " + bMaxValue
                    + " INCREMENT BY " + bStepValue + " START WITH " + bStartValue
                    + " CACHE 20 NOORDER  NOCYCLE");
    }
}
